import re
import os
import ctypes
from datetime import datetime
from PyQt6.QtWidgets import QVBoxLayout, QHBoxLayout, QWidget, QTableWidgetItem, QHeaderView, QProgressBar
from PyQt6.QtCore import Qt, QTimer, QThread, pyqtSignal
from PyQt6.QtGui import QFont, QColor
from qfluentwidgets import (CardWidget, StrongBodyLabel, TitleLabel, LineEdit,
                            ComboBox, PushButton, TableWidget, InfoBar,
                            InfoBarPosition, FluentIcon, setTheme, Theme)

try:
    import win32evtlog
    import win32evtlogutil
    import win32api
    WINDOWS_LOGS_AVAILABLE = True
except ImportError:
    WINDOWS_LOGS_AVAILABLE = False


class LogLoadThread(QThread):
    """Windows日志加载线程，避免UI卡顿"""
    logs_loaded = pyqtSignal(list)
    load_error = pyqtSignal(str)

    def __init__(self, max_entries=None):
        super().__init__()
        self.max_entries = max_entries

    def run(self):
        try:
            if not WINDOWS_LOGS_AVAILABLE:
                self.load_error.emit("缺少必要的Windows API库，请安装 pywin32")
                return

            log_entries = self.load_windows_logs()
            self.logs_loaded.emit(log_entries)
        except Exception as e:
            self.load_error.emit(f"加载Windows日志失败: {str(e)}")

    def is_admin(self):
        """检查是否有管理员权限"""
        try:
            return ctypes.windll.shell32.IsUserAnAdmin()
        except:
            return False

    def load_windows_logs(self):
        """加载Windows事件日志"""
        log_entries = []
        log_types = ["System", "Application"]

        print(f"当前权限: {'管理员' if self.is_admin() else '普通用户'}")
        print(f"将读取日志类型: {', '.join(log_types)}")

        for log_type in log_types:
            try:
                print(f"正在读取 {log_type} 日志...")
                entries = self.read_event_log(log_type)
                log_entries.extend(entries)
                print(f"{log_type} 日志读取完成，获得 {len(entries)} 条记录")
            except Exception as e:
                print(f"读取 {log_type} 日志失败: {e}")
                continue

        log_entries.sort(key=lambda x: x['raw_time'], reverse=True)
        return log_entries[:self.max_entries]

    def read_event_log(self, log_type):
        """读取指定类型的事件日志"""
        entries = []
        try:
            hand = win32evtlog.OpenEventLog(None, log_type)
            flags = win32evtlog.EVENTLOG_BACKWARDS_READ | win32evtlog.EVENTLOG_SEQUENTIAL_READ
            # total_read = 0 # 不再需要这个计数器
            batch_size = 100 # 仍然保持分批读取，避免内存瞬间压力

            while True: # 修改循环条件为 True，实现无限读取
                events = win32evtlog.ReadEventLog(hand, flags, 0)
                if not events: # 如果没有更多事件，就退出循环
                    break

                for event in events:
                    # 移除 total_read >= self.max_entries 的判断
                    try:
                        entry = self.parse_event(event, log_type)
                        if entry:
                            entries.append(entry)
                            # total_read += 1 # 不再需要这个计数器
                    except Exception as e:
                        print(f"解析事件失败: {e}")
                        continue
            return entries
        except Exception as e:
            raise Exception(f"无法打开 {log_type} 日志: {e}")
        finally:
            try:
                win32evtlog.CloseEventLog(hand)
            except:
                pass

    def parse_event(self, event, log_type):
        """解析单个事件记录"""
        try:
            timestamp = event.TimeGenerated
            timestamp_str = timestamp.strftime("%Y-%m-%d %H:%M:%S")
            level = self.get_event_level(event.EventType)
            source = event.SourceName if event.SourceName else "未知来源"
            message = self.get_event_message(event)
            event_id = event.EventID & 0xFFFF
            full_message = f"事件ID: {event_id}\n{message}"
            display_message = message[:500] + ("..." if len(message) > 500 else "")

            return {
                'timestamp': timestamp_str,
                'raw_time': timestamp,
                'level': level,
                'source': f"{log_type}/{source}",
                'message': display_message,
                'full_message': full_message,
                'event_id': event_id,
                'log_type': log_type
            }
        except Exception as e:
            print(f"解析事件详情失败: {e}")
            return None

    def get_event_message(self, event):
        try:
            try:
                message = win32evtlogutil.SafeFormatMessage(event, None)
                if message:
                    return message.strip()
            except:
                pass
            if hasattr(event, 'StringInserts') and event.StringInserts:
                messages = [str(insert).strip() for insert in event.StringInserts if insert and str(insert).strip()]
                if messages:
                    return " | ".join(messages)
            message_parts = []
            if hasattr(event, 'EventCategory') and event.EventCategory:
                message_parts.append(f"类别: {event.EventCategory}")
            message_parts.append(f"事件ID: {event.EventID & 0xFFFF}")
            return " | ".join(message_parts) if message_parts else "无详细消息"
        except Exception as e:
            return f"获取消息失败: {str(e)}"

    def get_event_level(self, event_type):
        level_map = {
            win32evtlog.EVENTLOG_ERROR_TYPE: "ERROR",
            win32evtlog.EVENTLOG_WARNING_TYPE: "WARNING",
            win32evtlog.EVENTLOG_INFORMATION_TYPE: "INFO",
            win32evtlog.EVENTLOG_AUDIT_SUCCESS: "INFO",
            win32evtlog.EVENTLOG_AUDIT_FAILURE: "ERROR"
        }
        return level_map.get(event_type, "INFO")


class LogFilterThread(QThread):
    """日志过滤线程"""
    filtered_logs = pyqtSignal(list)

    def __init__(self, log_entries, search_text, level_filter, log_type_filter):
        super().__init__()
        self.log_entries = log_entries
        self.search_text = search_text
        self.level_filter = level_filter
        self.log_type_filter = log_type_filter

    def run(self):
        filtered_entries = []
        for entry in self.log_entries:
            if self.search_text:
                if (self.search_text not in entry['message'].lower() and
                        self.search_text not in entry['source'].lower() and
                        self.search_text not in entry['full_message'].lower()):
                    continue
            if self.level_filter != "全部级别" and entry['level'] != self.level_filter:
                continue
            if self.log_type_filter != "全部类型" and entry['log_type'] != self.log_type_filter:
                continue
            filtered_entries.append(entry)
        self.filtered_logs.emit(filtered_entries)


class LogAnalyzer(QWidget):
    def __init__(self):
        super().__init__()
        self.MAX_LOG_ENTRIES = 1000  # 最大日志条数
        self.REFRESH_INTERVAL = 300000  # 自动刷新间隔(5分钟)
        self.SEARCH_DELAY = 300  # 搜索延迟(毫秒)
        self.PAGE_SIZE = 50  # 每页显示的日志条数

        self.log_entries = []
        self.filtered_entries = []
        self.displayed_entries = []
        self.current_page = 0
        self.load_thread = None
        self.filter_thread = None

        self.init_ui()
        self.setup_search_timer()
        self.load_logs()
        self.setup_auto_refresh()

    def init_ui(self):
        setTheme(Theme.LIGHT)
        self.setFont(QFont("Microsoft YaHei", 10))
        self.setWindowTitle("系统日志分析")
        self.setMinimumSize(1000, 700)

        layout = QVBoxLayout(self)
        layout.setContentsMargins(30, 30, 30, 30)
        layout.setSpacing(20)

        title_label = TitleLabel("系统日志分析")
        layout.addWidget(title_label)

        control_card = CardWidget()
        control_layout = QHBoxLayout(control_card)
        control_layout.setContentsMargins(15, 15, 15, 15)

        self.search_input = LineEdit()
        self.search_input.setPlaceholderText("搜索关键词（支持消息内容和来源搜索）...")
        self.search_input.setFixedWidth(300)
        self.search_input.textChanged.connect(self.on_search_text_changed)

        self.level_combo = ComboBox()
        self.level_combo.addItems(["全部级别", "INFO", "WARNING", "ERROR"])
        self.level_combo.setFixedWidth(120)
        self.level_combo.currentIndexChanged.connect(self.filter_logs)

        self.log_type_combo = ComboBox()
        self.log_type_combo.addItems(["全部类型", "System", "Application"])
        self.log_type_combo.setFixedWidth(120)
        self.log_type_combo.currentIndexChanged.connect(self.filter_logs)

        self.refresh_btn = PushButton("刷新日志", self, FluentIcon.SYNC)
        self.refresh_btn.clicked.connect(self.load_logs)
        self.refresh_btn.setFixedWidth(120)

        export_btn = PushButton("导出报告", self, FluentIcon.SAVE)
        export_btn.clicked.connect(self.export_report)
        export_btn.setFixedWidth(120)

        clear_btn = PushButton("清除筛选", self, FluentIcon.SETTING)
        clear_btn.clicked.connect(self.clear_filters)
        clear_btn.setFixedWidth(120)

        control_layout.addWidget(self.search_input)
        control_layout.addWidget(self.level_combo)
        control_layout.addWidget(self.log_type_combo)
        control_layout.addWidget(self.refresh_btn)
        control_layout.addWidget(export_btn)
        control_layout.addWidget(clear_btn)
        control_layout.addStretch()
        layout.addWidget(control_card)

        # 进度条
        self.progress_bar = QProgressBar()
        self.progress_bar.setVisible(False)
        self.progress_bar.setFixedHeight(8)
        layout.addWidget(self.progress_bar)

        log_card = CardWidget()
        log_layout = QVBoxLayout(log_card)
        log_layout.setContentsMargins(15, 15, 15, 15)
        log_layout.addWidget(StrongBodyLabel("日志记录"))

        self.log_table = TableWidget()
        self.log_table.setColumnCount(5)
        self.log_table.setHorizontalHeaderLabels(["时间", "级别", "类型", "来源", "消息"])
        header = self.log_table.horizontalHeader()
        header.setSectionResizeMode(0, QHeaderView.ResizeMode.ResizeToContents)
        header.setSectionResizeMode(1, QHeaderView.ResizeMode.ResizeToContents)
        header.setSectionResizeMode(2, QHeaderView.ResizeMode.ResizeToContents)
        header.setSectionResizeMode(3, QHeaderView.ResizeMode.ResizeToContents)
        header.setSectionResizeMode(4, QHeaderView.ResizeMode.Stretch)
        self.log_table.setAlternatingRowColors(True)
        self.log_table.setSelectionBehavior(TableWidget.SelectionBehavior.SelectRows)

        # 分页导航
        pagination_layout = QHBoxLayout()
        self.prev_page_btn = PushButton("上一页", self, FluentIcon.LEFT_ARROW)
        self.prev_page_btn.clicked.connect(self.prev_page)
        self.next_page_btn = PushButton("下一页", self, FluentIcon.RIGHT_ARROW)
        self.next_page_btn.clicked.connect(self.next_page)
        self.page_label = StrongBodyLabel("第 1 页 / 共 1 页")
        pagination_layout.addWidget(self.prev_page_btn)
        pagination_layout.addWidget(self.page_label)
        pagination_layout.addWidget(self.next_page_btn)
        pagination_layout.addStretch()

        log_layout.addWidget(self.log_table)
        log_layout.addLayout(pagination_layout)
        layout.addWidget(log_card)

    def setup_search_timer(self):
        self.search_timer = QTimer()
        self.search_timer.setSingleShot(True)
        self.search_timer.timeout.connect(self.filter_logs)

    def on_search_text_changed(self):
        self.search_timer.stop()
        self.search_timer.start(self.SEARCH_DELAY)

    def clear_filters(self):
        self.search_input.clear()
        self.level_combo.setCurrentIndex(0)
        self.log_type_combo.setCurrentIndex(0)
        self.filter_logs()

    def load_logs(self):
        if self.load_thread and self.load_thread.isRunning():
            InfoBar.warning(
                title="请稍候",
                content="日志正在加载中，请等待完成...",
                orient=Qt.Orientation.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP_RIGHT,
                duration=2000,
                parent=self
            )
            return

        # 禁用刷新按钮
        self.refresh_btn.setEnabled(False)
        self.progress_bar.setVisible(True)
        self.progress_bar.setRange(0, 0)  # 不确定进度模式

        # self.load_thread = LogLoadThread(self.MAX_LOG_ENTRIES)
        self.load_thread = LogLoadThread(max_entries=None)
        self.load_thread.logs_loaded.connect(self.on_logs_loaded)
        # self.load_thread.load_error.connect(self.on_load_error)
        self.load_thread.finished.connect(self.on_load_thread_finished)
        self.load_thread.start()

        InfoBar.info(
            title="正在加载",
            content="正在读取Windows系统日志，请稍候...",
            orient=Qt.Orientation.Horizontal,
            isClosable=True,
            position=InfoBarPosition.TOP_RIGHT,
            duration=2000,
            parent=self
        )

    def on_load_thread_finished(self):
        """线程完成后的清理工作"""
        self.refresh_btn.setEnabled(True)
        self.progress_bar.setVisible(False)

    def on_logs_loaded(self, log_entries):
        self.log_entries = log_entries
        self.filter_logs()

        total = len(self.log_entries)
        errors = sum(1 for e in self.log_entries if e['level'] == 'ERROR')
        warnings = sum(1 for e in self.log_entries if e['level'] == 'WARNING')

        InfoBar.success(
            title="加载完成",
            content=f"成功加载 {total} 条日志记录 | 错误: {errors} | 警告: {warnings}",
            orient=Qt.Orientation.Horizontal,
            isClosable=True,
            position=InfoBarPosition.TOP_RIGHT,
            duration=3000,
            parent=self
        )

    def filter_logs(self):
        if self.filter_thread and self.filter_thread.isRunning():
            return

        search_text = self.search_input.text().lower()
        level_filter = self.level_combo.currentText()
        log_type_filter = self.log_type_combo.currentText()

        self.filter_thread = LogFilterThread(self.log_entries, search_text, level_filter, log_type_filter)
        self.filter_thread.filtered_logs.connect(self.on_filtered_logs)
        self.filter_thread.start()

    def on_filtered_logs(self, filtered_entries):
        self.filtered_entries = filtered_entries
        self.current_page = 0
        self.update_table()
        self.update_pagination()

    def update_table(self):
        """分批更新表格显示"""
        self.log_table.setRowCount(0)  # 清空表格
        start_idx = self.current_page * self.PAGE_SIZE
        end_idx = min(start_idx + self.PAGE_SIZE, len(self.filtered_entries))
        self.displayed_entries = self.filtered_entries[start_idx:end_idx]

        self.log_table.setRowCount(len(self.displayed_entries))

        for row, entry in enumerate(self.displayed_entries):
            time_item = QTableWidgetItem(entry['timestamp'])
            time_item.setFont(QFont("Consolas", 9))

            level_item = QTableWidgetItem(entry['level'])
            level_color = self.get_level_color(entry['level'])
            if level_color:
                level_item.setForeground(level_color)
            level_item.setFont(QFont("Microsoft YaHei", 9, QFont.Weight.Bold))

            type_item = QTableWidgetItem(entry['log_type'])
            source_parts = entry['source'].split('/', 1)
            source_item = QTableWidgetItem(source_parts[1] if len(source_parts) > 1 else entry['source'])
            message_item = QTableWidgetItem(entry['message'])
            message_item.setToolTip(entry['full_message'])

            self.log_table.setItem(row, 0, time_item)
            self.log_table.setItem(row, 1, level_item)
            self.log_table.setItem(row, 2, type_item)
            self.log_table.setItem(row, 3, source_item)
            self.log_table.setItem(row, 4, message_item)

    def update_pagination(self):
        """更新分页信息"""
        total_pages = max(1, (len(self.filtered_entries) + self.PAGE_SIZE - 1) // self.PAGE_SIZE)
        self.page_label.setText(f"第 {self.current_page + 1} 页 / 共 {total_pages} 页")
        self.prev_page_btn.setEnabled(self.current_page > 0)
        self.next_page_btn.setEnabled(self.current_page < total_pages - 1)

    def prev_page(self):
        if self.current_page > 0:
            self.current_page -= 1
            self.update_table()
            self.update_pagination()

    def next_page(self):
        total_pages = (len(self.filtered_entries) + self.PAGE_SIZE - 1) // self.PAGE_SIZE
        if self.current_page < total_pages - 1:
            self.current_page += 1
            self.update_table()
            self.update_pagination()

    def get_level_color(self, level):
        color_map = {
            "ERROR": QColor("#FF4444"),
            "WARNING": QColor("#FF8800"),
            "INFO": QColor("#0066CC")
        }
        return color_map.get(level)

    def export_report(self):
        if not self.log_entries:
            InfoBar.warning(
                title="无数据",
                content="没有可导出的日志数据",
                orient=Qt.Orientation.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP_RIGHT,
                duration=2000,
                parent=self
            )
            return

        try:
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            filename = f"Windows日志分析报告_{timestamp}.txt"

            total = len(self.log_entries)
            filtered = len(self.filtered_entries)
            stats = self.get_log_statistics()

            with open(filename, 'w', encoding='utf-8') as f:
                f.write("=" * 60 + "\n")
                f.write("Windows系统日志分析报告\n")
                f.write("=" * 60 + "\n")
                f.write(f"报告生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
                f.write(f"操作系统: Windows\n")
                f.write(f"管理员权限: {'是' if self.is_admin() else '否'}\n")
                f.write(f"总记录数: {total}\n")
                f.write(f"当前显示: {filtered}\n\n")
                f.write("日志级别统计:\n")
                f.write("-" * 30 + "\n")
                for level, count in stats['levels'].items():
                    f.write(f"{level:12}: {count:6} 条\n")
                f.write("\n")
                f.write("日志类型统计:\n")
                f.write("-" * 30 + "\n")
                for log_type, count in stats['types'].items():
                    f.write(f"{log_type:12}: {count:6} 条\n")
                f.write("\n")
                if stats['error_sources']:
                    f.write("错误来源统计 (前10):\n")
                    f.write("-" * 30 + "\n")
                    for source, count in list(stats['error_sources'].items())[:10]:
                        f.write(f"  {source}: {count} 个错误\n")
                    f.write("\n")
                f.write("详细日志记录:\n")
                f.write("=" * 60 + "\n")
                for entry in self.filtered_entries:
                    f.write(f"时间: {entry['timestamp']}\n")
                    f.write(f"级别: {entry['level']}\n")
                    f.write(f"类型: {entry['log_type']}\n")
                    f.write(f"来源: {entry['source']}\n")
                    f.write(f"消息: {entry['full_message']}\n")
                    f.write("-" * 60 + "\n")

            InfoBar.success(
                title="导出成功",
                content=f"报告已保存为 {filename}",
                orient=Qt.Orientation.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP_RIGHT,
                duration=3000,
                parent=self
            )
        except Exception as e:
            InfoBar.error(
                title="导出失败",
                content=str(e),
                orient=Qt.Orientation.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP_RIGHT,
                duration=3000,
                parent=self
            )

    def get_log_statistics(self):
        stats = {
            'levels': {},
            'types': {},
            'error_sources': {}
        }
        for entry in self.log_entries:
            level = entry['level']
            stats['levels'][level] = stats['levels'].get(level, 0) + 1
            log_type = entry['log_type']
            stats['types'][log_type] = stats['types'].get(log_type, 0) + 1
            source = entry['source']
            if level == 'ERROR':
                stats['error_sources'][source] = stats['error_sources'].get(source, 0) + 1
        stats['error_sources'] = dict(sorted(stats['error_sources'].items(),
                                             key=lambda x: x[1], reverse=True))
        return stats

    def is_admin(self):
        try:
            return ctypes.windll.shell32.IsUserAnAdmin()
        except:
            return False

    def setup_auto_refresh(self):
        self.auto_refresh_timer = QTimer()
        self.auto_refresh_timer.timeout.connect(self.load_logs)
        self.auto_refresh_timer.start(self.REFRESH_INTERVAL)

    def closeEvent(self, event):
        if self.load_thread and self.load_thread.isRunning():
            self.load_thread.quit()
            self.load_thread.wait()
        if self.filter_thread and self.filter_thread.isRunning():
            self.filter_thread.quit()
            self.filter_thread.wait()
        event.accept()